{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit L20_modClassesConstruction;

interface


uses Classes,
     SysUtils,
     modCookies,
     modCore,
     modBaseType,
     modParsingClass,
     HttpProt,
     Forms,
     Windows,
     modCoreRecu,
     ESBDates,
     sFonctionsChaines,
     sHTMLFonctions,
     modGestionDownload,
     modGestionDLGzip,

     modSockUtils,

     modClassRessources,
     modPlanete,
     modLinkOtherPlanet,
     modActionManager,
     modStatsPlayers,
     modMessagesList,
     modGalaxiePlanetes,

     modGIDtoSTR,            // GID to STR

     WSocket,
     modAlarmeAttaque,
     modFlotteTracking,

     modClasses,
     L10_modClassesAlerteAtt,

     modParsingClassIMenuLeft,
     
     modProfilsForAttack;


type
     TPlayerGestionConstruct =  class(TPlayerGestionAlerteAtt)
     private

        FConstructionAutoEnable: boolean;


        FCallBackOnItemsCostChange: TCallBackOnItemsCostChange;

        
        procedure Init;

        // non utilisé
        function TryExecuteActionPlanete: integer;

        // ne fonctionne pas encore
        function AdjustRessourceForTheNextItem: integer;




        procedure TraitementActionPlanete(p: TPlaneteInfo);
        function ExecuteActionElement(Action: PElementActionItem): TBasicActionResult;

        function ExecuteActionAdv(NextAct: PElementActionItem; var pe1: POGItemCost; p: TPlaneteInfo): TBasicActionResult;

     public
        // Call back utile pour le GUI permettant de savoir quand es-ce que
        // les éléments ont été mis à jour
        property CallBackOnItemsCostChange: TCallBackOnItemsCostChange read FCallBackOnItemsCostChange write FCallBackOnItemsCostChange;

        // Active/Désactive la construction automatique
        property ConstructionAutoEnable   : boolean                    read FConstructionAutoEnable    write FConstructionAutoEnable;




        procedure OnTimer; override;

        function ProceedUpdateElement(IdFromMenu: TMenuLinkID; bDoUpdateItem: boolean = true): integer; override;

        constructor Create;

        procedure ShowInternal; override;
     end;


implementation

uses gnugettext;

procedure TPlayerGestionConstruct.ShowInternal;
begin

        inherited ShowInternal;

        DoDebug('@@@@@ Construction automatique @@@@@');


        DoDebugInt('FinRecherche', allPlanetes.ActionDateFinRecherche);


        DoDebugInt('Enable', iif(FConstructionAutoEnable, 1, 0));


        DoDebug('Callback: 0x' + IntToHex(Cardinal(@FCallBackOnItemsCostChange), 8));


end;

function TPlayerGestionConstruct.AdjustRessourceForTheNextItem: integer;
begin
    {$IFDEF DEBUG}
       DoDebug('AdjustRessourceForTheNextItem - Start');
    {$ENDIF}
end;


constructor TPlayerGestionConstruct.Create;
begin
    inherited Create;

    FCallBackOnItemsCostChange := nil;
    Init;
end;

function TPlayerGestionConstruct.ProceedUpdateElement(IdFromMenu: TMenuLinkID; bDoUpdateItem: boolean = true): integer;
begin

    Result := inherited ProceedUpdateElement(IdFromMenu, bDoUpdateItem);

    if Result > 0 then begin
          if Assigned(FCallBackOnItemsCostChange) then begin
             FCallBackOnItemsCostChange(Self, curPlanete);
          end;
    end;
end;

procedure TPlayerGestionConstruct.OnTimer;
var p: TPlaneteInfo;
    i: integer;
begin

    inherited OnTimer;

    if IsLoggedAndCanDoSomething = false then begin
       exit;
    end;

    if FConstructionAutoEnable then begin
       for i := 0 to allPlanetes.Count - 1 do begin
          p := allPlanetes.Items[i];
          TraitementActionPlanete(p);
       end;

    end;

    
end;

procedure TPlayerGestionConstruct.TraitementActionPlanete(p: TPlaneteInfo);
var Resultat: TBasicActionResult;
    uAction: PElementActionItem;
    pe1: POGItemCost;

    i64Duree: int64;
    gidTypeExecuted, gidTypeNextAct: integer;
begin

    if p = nil then begin
       {$IFDEF DEBUG}
          DoDebug(_('TraitementActionPlanete - Planete NIL'));
       {$ENDIF}
       exit;
    end;


    if p.cActions.Count = 0 then exit;
    if sockHTTP.State <> httpReady then begin
       {$IFDEF DEBUG}
          DoDebug('TraitementActionPlanete - ' + p.pLocationStr + _(' - Socket non pret'));
       {$ENDIF}
       exit;
    end;


    LastCurrDate := DateTimeToUnix(Now);

    if (p.ActionDateCanRetry > 100) and (LastCurrDate < p.ActionDateCanRetry) then begin
       // On doit un peu attendre
       {$IFDEF DEBUG}
          i64Duree := p.ActionDateCanRetry - LastCurrDate;

          if (i64Duree mod 15) = 0 then begin
             DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' - Durée restante: ' + ESBDGetDureeStrings(i64Duree, true) + '  (' + p.FNom + ')');
          end;

       {$ENDIF}
       exit;
    end;


    // Obtient une action
    uAction := p.cActions.GetNextActionToDo;
    if uAction = nil then exit;


    if (p.FLastRessourcesDate < 100) or (p.FLastRessourcesDate < (LastCurrDate - 900)) then begin
       // Met à jour les ressources toute les demi-heure au cas où des vaisseaux
       // amènerai des ressources
       {$IFDEF DEBUG}
          DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' - Update planète au cas où des flottes auraient apportées des ressources');
       {$ENDIF}

       if ChangePlanete(p.FLocation) >= 0 then begin
          // Et en profite pour télécharger la production
          if ProceedUpdateRessource(true, false) < 0 then begin
             // echec de mise à jour des ressources
             {$IFDEF DEBUG}
                DoDebug('TraitementActionPlanete - ' + p.pLocationStr + _(' - Echec de mise à jour des ressources'));
             {$ENDIF}
          end;

       end else begin
          // echec de changement de planète
          {$IFDEF DEBUG}
             DoDebug('TraitementActionPlanete - ' + p.pLocationStr + _(' - Echec de changement de planète'));
          {$ENDIF}
          exit;
       end;


    end;

    if p.ActionDateFinBatiment < LastCurrDate then begin
       // le bâtiment a été construit
       // es-ce que l'on a calculé les ressources entre temps ?

       if p.ActionDateDernierCalculRessource > p.ActionDateFinBatiment then begin
          // les ressources ont déjà été calculé

       end else begin
          // les ressources n'ont pas été calculé
          if ChangePlanete(p.FLocation) >= 0 then begin
             if ProceedUpdateRessource(true, true) < 0 then begin
                // echec de mise à jour des ressources
                {$IFDEF DEBUG}
                   DoDebug('TraitementActionPlanete - ' + p.pLocationStr + _(' - Echec de mise à jour des ressources'));
                {$ENDIF}
             end;
          end;

       end;

    end;


    // Change de planète dans la fonction Adv
    pe1 := nil;
    Resultat := ExecuteActionAdv(uAction, pe1, p);

    case Resultat of
         basERREUR_FATALE : begin
                         uAction.Status := ACTION_STATUS_ENATTENTE;
                      end;

         basMUST_RELOGIN: begin
                         // ExecuteActionAdv NE se relog PLUS tout seul
                         uAction.Status := ACTION_STATUS_ENATTENTE;

                         if ProceedLogin <= 0 then begin
                            {$IFDEF DEBUG}
                               DoDebug(_('Relogin échec'));
                            {$ENDIF}

                            p.ActionDateCanRetry := DateTimeToUnix(Now) + 120;
                         end;

                      end;

         basGID_NEEDMORERESSOURCE: begin
                         // Es-ce du à une impossibilité de production des ressources
                         // ou l'élément sera constructible dans plus ou moins longtemps ?

                         if pe1 <> nil then begin
                            if pe1.CanBeBuildIn = CNT_CONSTRUCTION_DISPO_NEVER_WITHTHISPROD then begin
                               // inconstructible avec cette production
                               uAction.Status := ACTION_STATUS_GID_CANTBEBUILDWITHTHISPRODUCTION;
                            end;
                         end;

                      end;

         basAUTRE_CONSTRUCTION_ENCOURS: begin
                         uAction.Status := ACTION_STATUS_ENATTENTE;
                      end;

         basGID_NONDISPONIBLE: begin
                         // GID non disponible, on doit passer à l'action suivante
                         uAction.Status := ACTION_STATUS_GIDNONDISPONIBLE;
                     end;

         basACTION_EFFECTUE: begin
                         uAction.Status   := ACTION_STATUS_EFFECTUE;
                         uAction.DateDone := LastCurrDate;

                         gidTypeExecuted := GetTypeOfGID(uAction.Gid);

                         uAction := p.cActions.GetNextActionToDo;
                         if uAction = nil then begin
                            // plus d'action
                            {$IFDEF DEBUG}
                               DoDebug('TraitementActionPlanete - ' + p.pLocationStr + _(' - Toutes les actions ont été effectué'));
                            {$ENDIF}

                         end else begin
                            gidTypeNextAct  := GetTypeOfGID(uAction.Gid);

                            if gidTypeExecuted <> gidTypeNextAct then begin
                               // deux type différents
                               // on n'a certainement pas besoin d'attendre que l'une se termine
                               // pour lancer l'autre

                               {$IFDEF DEBUG}
                                  DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' - Deux actions de type différent');
                               {$ENDIF}

                               if gidTypeNextAct = CNT_ITEM_DESIGN_RECHERCHE then begin
                                  // c'est une recherche
                                  {$IFDEF DEBUG}
                                      DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' Le prochain élément est une recherche');
                                  {$ENDIF}



                                  if (allPlanetes.ActionDateFinRecherche > 100)  then begin
                                      if (LastCurrDate < allPlanetes.ActionDateFinRecherche) then begin
                                         // la recherche n'est pas encore terminée
                                         p.ActionDateCanRetry := allPlanetes.ActionDateFinRecherche;

                                         {$IFDEF DEBUG}
                                             DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' -> Fixe le délai de lancement à la fin de la recherche en cours');
                                         {$ENDIF}

                                      end else begin
                                         // la recherche est terminée

                                         p.ActionDateCanRetry := LastCurrDate + 5;
                                         {$IFDEF DEBUG}
                                             DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' -> On peut la lancer: Raccourcissement du délai');
                                         {$ENDIF}
                                      end;

                                  end else  begin
                                      // aucune information sur l'état des recherches
                                      p.ActionDateCanRetry := LastCurrDate + 5;

                                      {$IFDEF DEBUG}
                                          DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' -> Aucune informations sur l''état des recherches: Raccourcissement du délai');
                                      {$ENDIF}
                                  end;


                               end else if gidTypeNextAct = CNT_ITEM_DESIGN_BATIMENT then begin
                                  // c'est un bâtiment
                                  {$IFDEF DEBUG}
                                      DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' Le prochain élément est un bâtiment');
                                  {$ENDIF}

                                  if p.ActionDateFinBatiment > 100 then begin
                                     if (LastCurrDate < p.ActionDateFinBatiment) then begin
                                         // le bâtiment n'est pas encore terminée
                                         p.ActionDateCanRetry := p.ActionDateFinBatiment;

                                         {$IFDEF DEBUG}
                                             DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' -> Fixe le délai de lancement à la fin du bâtiment en cours');
                                         {$ENDIF}

                                     end else  begin
                                         // le batiment est terminée
                                         p.ActionDateCanRetry := LastCurrDate + 5;
                                         {$IFDEF DEBUG}
                                             DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' -> On peut le lancer: Raccourcissement du délai');
                                         {$ENDIF}
                                     end;

                                  end else begin
                                     // aucune information sur l'état des bâtiments
                                      p.ActionDateCanRetry := LastCurrDate + 5;

                                      {$IFDEF DEBUG}
                                          DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' -> Aucune informations sur l''état des bâtiments: Raccourcissement du délai');
                                      {$ENDIF}
                                  end;


                               end else begin
                                  // non géré
                                  {$IFDEF DEBUG}
                                       DoDebug('TraitementActionPlanete - ' + p.pLocationStr + ' GID inconnu ou Non géré');
                                  {$ENDIF}
                               end;


                            end;
                         end;


                     end;
    end;

end;


function TPlayerGestionConstruct.ExecuteActionAdv(NextAct: PElementActionItem; var pe1: POGItemCost; p: TPlaneteInfo): TBasicActionResult;
var
    pe1Duree: integer;
    iResult: integer;
begin

    if p = nil then begin
       Result := basERREUR_FATALE;
       {$IFDEF DEBUG}
          DoDebug('TryExecuteActionPlaneteSimple - Paramètre planète p à nil');
       {$ENDIF}

       exit;
    end;

    if NextAct = nil then begin
       Result := basERREUR_FATALE;
       {$IFDEF DEBUG}
          DoDebug('TryExecuteActionPlaneteSimple - Paramètre action NextAct à nil');
       {$ENDIF}

       exit;
    end;

    {$IFDEF DEBUG}
       DoDebug('TryExecuteActionPlaneteSimple - Start Planète: ' + p.FNom  + ' [' + p.pLocationStr + ']');
    {$ENDIF}


    if curPlanete = nil then begin
       Result := basMUST_RELOGIN;
       {$IFDEF DEBUG}
          DoDebug('TryExecuteActionPlaneteSimple - Aucune planète en cours');
       {$ENDIF}

       exit;
    end;

    if p.cActions.Count = 0 then begin
       Result := basERREUR_FATALE;
       {$IFDEF DEBUG}
          DoDebug('TryExecuteActionPlaneteSimple - Aucune action trouvée');
       {$ENDIF}

       exit;
    end;

    // Extrait la ressource
    pe1 := p.cElements.GetGidItem(NextAct.Gid);
    pe1Duree := -1;

    if pe1 <> nil then begin

       if pe1.Prix.Metal > p.pEstimatedRessources.Metal then begin
          // Pas assez de métal
          {$IFDEF DEBUG}
             DoDebug(format('TryExecuteActionPlaneteSimple - Pas assez de métal, requis:%d  disponible:%d', [pe1.Prix.Metal, p.pEstimatedRessources.Metal]));
          {$ENDIF}

          p.ActionDateCanRetry := LastCurrDate + 60;
          Result := basGID_NEEDMORERESSOURCE;
          exit;

       end else if pe1.Prix.Cristal > p.pEstimatedRessources.Cristal then begin
          // Pas assez de Cristal
          {$IFDEF DEBUG}
              DoDebug(format('TryExecuteActionPlaneteSimple - Pas assez de Cristal, requis:%d  disponible:%d', [pe1.Prix.Cristal, p.pEstimatedRessources.Cristal]));
          {$ENDIF}

          p.ActionDateCanRetry := LastCurrDate + 60;
          Result := basGID_NEEDMORERESSOURCE;
          exit;

       end else if pe1.Prix.Deuterium > p.pEstimatedRessources.Deuterium then begin
          // Pas assez de Cristal
          {$IFDEF DEBUG}
              DoDebug(format('TryExecuteActionPlaneteSimple - Pas assez de Deuterium, requis:%d  disponible:%d', [pe1.Prix.Deuterium, p.pEstimatedRessources.Deuterium]));
          {$ENDIF}

          p.ActionDateCanRetry := LastCurrDate + 60;
          Result := basGID_NEEDMORERESSOURCE;
          exit;
       end;

       pe1Duree := pe1.Duree;

    end else begin
       {$IFDEF DEBUG}
          DoDebug('TryExecuteActionPlaneteSimple - pe1 à nil, le gid ne doit pas être constructible');
       {$ENDIF}
    end;


    if p.CantBuildThisGIDMustWaitCarConstructEnCours(NextAct.GID) then begin
       // Il y a une autre construction en cours déjà (qui est géré par le programme)
       Result := basAUTRE_CONSTRUCTION_ENCOURS;
       p.ActionDateCanRetry := LastCurrDate + 60;
       exit;
    end;


    iResult := ChangePlanete(p.FLocation);
    if iResult < 0 then begin
       // Erreur de changement de planète

       if iResult = CNT_ERROR_MUST_RELOGIN then begin
          Result := basMUST_RELOGIN;
          {$IFDEF DEBUG}
              DoDebug('TraitementActionPlanete - Erreur pour le changement de planète (Doit se relogger)');
          {$ENDIF}

       end else if iResult = CNT_ERROR_SOCKET then begin
          Result := basERREUR_FATALE;
          {$IFDEF DEBUG}
              DoDebug('TraitementActionPlanete - Erreur de socket pour le changement de planète');
          {$ENDIF}

       end else if iResult = CNT_ERROR_PARSING then begin
          Result := basERREUR_FATALE;
          {$IFDEF DEBUG}
              DoDebug('TraitementActionPlanete - Erreur de parsing du changement de planète');
          {$ENDIF}

       end else begin
          Result := basERREUR_FATALE;
          {$IFDEF DEBUG}
              DoDebug('TraitementActionPlanete - Erreur de changement de planète');
          {$ENDIF}

       end;
       exit;
    end;



    // Sinon il y a assez de ressources
    Result := ExecuteActionElement(NextAct);

    // Obtient à nouveau le pointeur
    pe1 := p.cElements.GetGidItem(NextAct.Gid);

    if pe1 <> nil then
       pe1Duree := pe1.Duree;

    case Result of
         basERREUR_FATALE : begin
                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - basERREUR_FATALE');
                         {$ENDIF}

                         p.ActionDateCanRetry := LastCurrDate + 900;  // 15mins
                      end;
         basERREUR_PARSING: begin
                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - Erreur parsing');
                         {$ENDIF}

                         p.ActionDateCanRetry := LastCurrDate + 19; //900;  // 15mins
                      end;
         basERREUR_SOCKET: begin
                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - Erreur socket');
                         {$ENDIF}

                         p.ActionDateCanRetry := LastCurrDate + 30;
                      end;

         basMUST_RELOGIN: begin
                         // Ne devrai jamais arrivé, car on a passé True à la fonction
                         {$IFDEF DEBUG}
                            DoDebug('TryExecuteActionPlaneteSimple - basSHOULD_RELOGIN');
                         {$ENDIF}

                         p.ActionDateCanRetry := LastCurrDate + 300;  // 10mins
                      end;

         basGID_NEEDMORERESSOURCE: begin
                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - basGID_NEEDMORERESSOURCE');
                         {$ENDIF}

                         p.ActionDateCanRetry := LastCurrDate + 120;  // 10mins car d'après le test ci-dessus, on a déjà toute les ressources qu'il faut
                      end;

         basAUTRE_CONSTRUCTION_ENCOURS: begin
                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - basAUTRE_CONSTRUCTION_ENCOURS');
                         {$ENDIF}

                         if (LastCurrDate - p.ActionDateFinBatiment) < 120 then begin
                            p.ActionDateCanRetry := LastCurrDate + 30;
                            {$IFDEF DEBUG}
                                DoDebug('+30');
                            {$ENDIF}

                         end else
                            p.ActionDateCanRetry := LastCurrDate + 400; // 10mins, action entreprise indépendament du programme

                      end;

         basGID_NONDISPONIBLE: begin
                         // GID non disponible, on doit passer à l'action suivante
                         // On utilise donc un délai court
                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - basGID_NONDISPONIBLE');
                         {$ENDIF}


                         p.ActionDateCanRetry := LastCurrDate + 120;
                     end;

         basACTION_EFFECTUE: begin
                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - basACTION_EFFECTUE');
                         {$ENDIF}


                         if NextAct <> nil then begin
                            NextAct.DateDone := LastCurrDate;
                         end;



                         if (pe1Duree > 0) and (pe1Duree < 1600) then begin
                            // la durée qui va prendre l'élément est connues
                            // cependant, il se peut qu'ensuite on veuille lancer
                            // une recherche au lieu d'un autre bâtiment
                            // (ou un bâtiment au lieu d'une autre recherche)
                            // -> ce problème a été résolu dans la fonction appellante

                            p.ActionDateCanRetry := LastCurrDate + pe1Duree + 14;

                         end else begin
                            // la durée est certainement connue, mais on utilise que 3mins
                            p.ActionDateCanRetry := LastCurrDate + 180; // 3mins
                         end;

                         {$IFDEF DEBUG}
                             DoDebug('TryExecuteActionPlaneteSimple - NextRetry=' + IntToStr(p.ActionDateCanRetry));
                         {$ENDIF}

                     end;
    end;


end;







//////////////////////////////////////////////
// Exécution simple d'une action, avec téléchargement obligé
// d'au moins une page, celle qui permet de lancer l'action pour vérifier si le
// Gid est bien disponible
//
// On doit déjà être sur la bonne planète avant d'appeller cette fonction
// La fonction ne s'occupe pas de l'auto relogin
function TPlayerGestionConstruct.ExecuteActionElement(Action: PElementActionItem): TBasicActionResult;
label lRedo, lMakeErr, lExecutedDoUpdate;
var pElement: POGItemCost;
    i, j: integer;
    iRedo: integer;
    bIsForm: boolean;
    
    sPageWeb, sHTTP: string;
    backupPlaneteLocation: TPlanetLocation;

    iResult: integer;

    iTypeOfElementToDL: TMenuLinkID;

    xGID: TTypeGID;

    (*
    function DoRelogin: TBasicActionResult;
    begin
        if bDoRelogingAuto then begin
           // On doit se relogger

           if ProceedLogin < 0 then begin
                // Il y a une erreur, ou le serveur est indisponible
                Result := basERREUR_FATALE;

           end else begin
                // Relogin Ok
                // On doit se repositionner sur la bonne planète
                ChangePlanete(backupPlaneteLocation);

                // On passe bien false à la fonction, car sinon on a une
                // 'boucle' infinit
                Result := ExecuteActionElement(Action, false);

                if Result = basSHOULD_RELOGIN then begin
                   // Il redemande de se relogger, or on vient de le faire
                   Result := basERREUR_FATALE;
                end;
           end;

        end else begin
             Result := basSHOULD_RELOGIN;
        end;

    end;
         *)

begin

    // Résultat par défaut
    Result := basERREUR_FATALE;

    if (Action = nil) or (curPlanete = nil) then
       exit;

       {$IFDEF DEBUG}
          DoDebug('ExecuteActionElement - Start');
       {$ENDIF}


    backupPlaneteLocation := curPlanete.FLocation;

    if Action.GID >= ACTION_GIDMISC_START then begin
       // Modification de ressources, ceci n'est pas gérer ici
       {$IFDEF DEBUG}
          DoDebug('ExecuteAction - Ne gère pas les ressouces');
       {$ENDIF}

       Result := basGID_NONDISPONIBLE;
       exit;

    end else begin
       // Construction d'un élément
       pElement := curPlanete.cElements.GetGidItem(Action.Gid);


       if pElement = nil then begin
          // Non disponible encore, mais peut-être devrions nous d'abord
          // mettre à jour la liste des GID, si par exemple quand on finit
          // l'évolution d'un bat ?
          {$IFDEF DEBUG}
              DoDebug('ExecuteAction - GID non trouvé dans la liste locale des éléments');
          {$ENDIF}
       end;

       // Sinon élément disponible, avant de télécharger la page du lien
       // pour lancer la construction, on télécharge la page permettant
       // la construction de ce même lien pour cacher le fait que l'on
       // utilise un programme, et aussi pour mettre à jour l'éventuel lien

       bIsForm := false;
       xGID := GetTypeOfTGID(Action.Gid);

       case xGID of
            tgidBatiment : iTypeOfElementToDL := mliBatiments;
            tgidRecherche: iTypeOfElementToDL := mliRecherche;
            tgidVaisseau : begin
                               iTypeOfElementToDL := mliChantierSpatial;
                               bIsForm := true;
                            end;   
            tgidDefense  : begin
                               iTypeOfElementToDL := mliDefense;
                               bIsForm := true;
                            end;
            else iTypeOfElementToDL := mliErreur;
       end;

       if iTypeOfElementToDL = mliErreur then begin
           {$IFDEF DEBUG}
              DoDebug('ExecuteAction - Element non identifié, page web inconnue');
           {$ENDIF}

           Result := basERREUR_FATALE;
           exit;
       end;

       // sinon on peut télécharger la page correspondante

       //try
         iResult := ProceedUpdateElement(iTypeOfElementToDL, true);
       //except
       //  iResult := -9994;
       //end;

       (*
       if iResult = -9994 then begin
          FJobOccupation := jobpAucun;
          iResult := ProceedUpdateElement(iTypeOfElementToDL, true);
       end;
       *)

       if iResult < 0 then begin
          // Erreur de téléchargement de la page, on devrait se relogger ?


          if iResult = CNT_ERROR_MUST_RELOGIN then begin
             // on doit se relogger
            {$IFDEF DEBUG}
                DoDebug('ExecuteAction - Erreur: Doit se relogger');
            {$ENDIF}

            Result := basMUST_RELOGIN;
            exit;

          end else if iResult = CNT_ERROR_SOCKET then begin
             // erreur de socket...
            {$IFDEF DEBUG}
                DoDebug('ExecuteAction - Erreur: Socket (Echec de téléchargement)');
            {$ENDIF}

            Result := basERREUR_SOCKET;
            exit;

          end else if iResult = CNT_ERROR_PARSING then begin
             // erreur de parsing
            {$IFDEF DEBUG}
                DoDebug('ExecuteAction - Erreur: Parsing');
            {$ENDIF}
            Result := basERREUR_PARSING;
            exit;

          end else if iResult = CNT_ERROR_FATAL then begin
             // erreur fatale
            {$IFDEF DEBUG}
                DoDebug('ExecuteAction - Erreur: Fatale');
            {$ENDIF}
             Result := basERREUR_FATALE;
             exit;

          end else begin
             // erreur inconnu
            {$IFDEF DEBUG}
                DoDebug('ExecuteAction - Erreur Fatale: id=' + IntToStr(iResult));
            {$ENDIF}
             Result := basERREUR_FATALE;
             exit;

          end;

       (*
          Sleep(200);
          Application.ProcessMessages;
          Sleep(250);
          Application.ProcessMessages;
          Sleep(250);

          // réessaye
          if ProceedUpdateElement(i, true) < 0 then begin
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - Erreur de téléchargement de page, la seconde tentative a aussi echoue');
             {$ENDIF}
             Result := DoRelogin;
             exit;
          end;
*)


       end else if iResult = 0 then begin
          // aucun élément dans la page web malgré le succés
          // il peut s'agir des défenses/chantier spatial
          // voir même du laboratoire
         {$IFDEF DEBUG}
            DoDebug('ExecuteAction - Aucun élément trouvé dans la page web...');
         {$ENDIF}

          Result := basGID_NONDISPONIBLE;
          exit;
       end;



       if cParsing.IsValidPage = false then begin
          // update 14/09/2006
          // L'erreur d'header est désormais considéré comme une erreur de parsing
          {$IFDEF DEBUG}
             DoDebug('ExecuteAction - Erreur de téléchargement de page - Header invalide');
          {$ENDIF}

          Result := basERREUR_PARSING;
          exit;
       end;

       // On ré-extrait le pointeur de LA PAGE WEB car il a été mis à jour
       // Update: Si le téléchargement réussi, ils sont mis dans les éléments
       // de la planète ET supprimer de la classe de parsing
       //pElement := cElement.Valeurs.GetGidItem(Action.Gid);
       pElement := curPlanete.cElements.GetGidItem(Action.Gid);



       // On vérifie que le GID existe bien dans la PAGE WEB
       if pElement = nil then begin
          Result        := basGID_NONDISPONIBLE;
          Action.Status := ACTION_STATUS_GIDNONDISPONIBLE;
          exit;
       end;


       // Le lien de référence est la page que l'on vient de télécharger
       sockHTTP.Reference := cParsing.LastPageURL;

       // On n'oublie pas les cookies
       sockHTTP.Cookie    := iCookies.GetCookieData;

       // debug
       {$IFDEF DEBUG}
          DoDebug('ExecuteAction - Lien de référence: ' + sockHTTP.Reference);
       {$ENDIF}


       if lowercase(copy(sockHTTP.Reference, 1, 4)) <> 'http' then begin
          // Erreur
          {$IFDEF DEBUG}
              DoDebug('ExecuteAction - Lien de la page "reference" incorrect: ' + sockHTTP.Reference);
          {$ENDIF}

          Result := basERREUR_FATALE;
          exit;
       end;


       curPlanete.cElements.SendToDebugAllInfo;



       if cParsing.pElements.FormAction = '' then begin
          // Simple lien à télécharger pour lancer la construction/recherche

          //

          //if (pElement.Link = '') or (curPlanete.cElements.CanBuildSomethingOfThisType(GetTypeOfGID(pElement.Gid)) = false) then begin

          if (pElement.Link = '') or (curPlanete.cElements.SomethingOfThisTypeIsInConstruction(GetTypeOfTGID(pElement.Gid)) = true) then begin


             // UPDATE: Le lien contient PARFOIS l'url pour annuler la construction
             //         car il se peut que la personne enchaine deux constructions du même élément

          
             // L'élément ne peut pas encore être construit

             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - L''élément ne peut pas encore être contruit');
             {$ENDIF}

             
             // Es-ce du à cause d'une autre construction ?
             if cParsing.pElements.CannotBuild then begin
                // Il y a déjà une construction en cours
                Result := basAUTRE_CONSTRUCTION_ENCOURS;
                exit;
             end;

             // Sinon c'est qu'il manque de ressource (ou plus de cases libres)
             Result := basGID_NEEDMORERESSOURCE;
             exit;

          end else if pElement.Duree <= 0 then begin
             // Impossible, l'élément a du mal être extrait de la page web
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - L''élément a mal été extrait de la page web (erreur de parsing de durée de construction)');
             {$ENDIF}

             Result := basERREUR_FATALE;
             exit;
          end;


          i := GetTypeOfGID(Action.GID);

          if (i = CNT_ITEM_DESIGN_RECHERCHE) or (i = CNT_ITEM_DESIGN_BATIMENT) then begin
             // ok
             i := 0;

          end else begin
             // Impossible
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - GID Invalide...');
             {$ENDIF}

             Result := basERREUR_FATALE;
             exit;
          end;


          // Définit le lien complet
          sHTTP := sHTML_Get_URL_Lien(sockHTTP.Reference, pElement.Link);

          {$IFDEF DEBUG}
              DoDebug('Page web - ' + sHTTP);
          {$ENDIF}


          if lowercase(copy(sHTTP, 1, 4)) <> 'http' then begin
             // Erreur
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - Lien de téléchargement incorrect: ' + sHTTP);
             {$ENDIF}

             Result := basERREUR_FATALE;
             exit;
          end;

          ///////////////////////////////////////////////////////////////
          // EXECUTE L'ACTION EN TELECHARGEANT LA PAGE WEB
          ///////////////////////////////////////////////////////////////

          iRedo := 0;
lRedo:

          if sockHTTP.State <> httpReady then begin
             // composant pas prêt
             Sleep(5);
          end;

          Inc(iRedo);
          sPageWeb := myGETorPOST_InTamponX(sHTTP, '', sockHTTP);

          if sPageWeb = modDL_ERREUR_DL_STR then begin
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - Erreur de téléchargement');
             {$ENDIF}

             DoSleep(1000);

             if iRedo > 7 then begin
                Result := basERREUR_SOCKET;
                exit;
             end;

             goto lRedo;

          end else if sPageWeb = mcDL_MUST_RELOGIN then begin
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - Doit se relogger');
             {$ENDIF}
             Result := basMUST_RELOGIN;
             exit;
          end;



          // Effectue quand même le parsing, le type de classe à
          // utiliser est donc cElement
          // On extrait les données de la page
          if cParsing.ParsingElements(sPageWeb) = false then begin
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - Le parsing a échoué');
             {$ENDIF}

             {$IFDEF DEBUGFILE_WHEN_ECHEC}
                 DebugWebPage(sPageWeb, CNT_DEBUGFILE_HEADER_INVALID);
             {$ENDIF}



             if cParsing.IsValidPage then begin
                // le serveur doit lagger ?
                {$IFDEF DEBUG}
                    DoDebug('ExecuteAction - La page n''est pas valide (le serveur doit lagger?)');
                {$ENDIF}

                if iRedo > 3 then begin
                   {$IFDEF DEBUG}
                       DoDebug('ExecuteAction - Trop d''esais - On télécharge la page "normalement" pour savoir si l''élément a été lancé');
                   {$ENDIF}

                   // on va télécharger simplement la page (sans l'action de construire)
                   // et on vérifie si la construction a été lancé
                   iResult := ProceedUpdateElement(iTypeOfElementToDL, true);

                   if iResult < 0 then begin
                      {$IFDEF DEBUG}
                          DoDebug('ExecuteAction - Encore une erreur...');
                      {$ENDIF}

                   end else begin


                       if cParsing.pElements.CannotBuild then begin
                          // l'élément a été exécuté
                          {$IFDEF DEBUG}
                                DoDebug('ExecuteAction - L''élément a été lancé');
                          {$ENDIF}

                          goto lExecutedDoUpdate;
                       end;
                   end;

                   Result := basERREUR_SOCKET;
                   exit;
                end;

                {$IFDEF DEBUG}
                    DoDebug('ExecuteAction - -> Réessaye');
                {$ENDIF}

                // on retélécharge la page web pour savoir si l'action a été effecté...
                goto lRedo;
             end;


             Result := basERREUR_PARSING;
             exit;
          end;


          cParsing.SetURLOfThisPage(sHTTP);

          // Gère les cookies
          iCookies.ParseHeader(sockHTTP.RcvdHeader);




          if (cParsing.IsValidPage = false)   then begin
             // update 14/09/2006
             // L'erreur d'header est désormais considéré comme une erreur de parsing
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - Header invalide');
             {$ENDIF}


             {$IFDEF DEBUGFILE_WHEN_ECHEC}
                 DebugWebPage(sPageWeb, CNT_DEBUGFILE_HEADER_INVALID);
             {$ENDIF}


             Result := basERREUR_PARSING;
             exit;

          end else if (cParsing.pElements.ElementsList.Count = 0) then begin
             {$IFDEF DEBUG}
                 DoDebug('ExecuteAction - Aucun élément dans la liste');
             {$ENDIF}

             Result := basGID_NONDISPONIBLE;
             exit;
          end;


          // Le parsing a réussi
          // On supprime les anciens éléments
          curPlanete.cElements.DeleteThisType(cParsing.pElements.GidType);

          // Ajoute les nouveaux éléments
          InjectTList(cParsing.pElements.ElementsList, curPlanete.cElements);

          // Ne libére pas les pointeurs puisqu'on vient de les injecter
          //cElement.DontFreePointeur := true;


          // les éléments sont maintenant géré par la classe des "planètes"
          // on peut les supprimer de la classe de parsing
          //cElement.Valeurs.Clear;
          cParsing.pElements.ElementsList.Clear;


          
          curPlanete.cElements.Trie;

          // CallBack pour raffraichir les éléments de la
          // grille
          if Assigned(FCallBackOnItemsCostChange) then begin
             FCallBackOnItemsCostChange(Self, curPlanete);
          end;

          // Met à jour la quantité de ressources
          curPlanete.FLastRessources     := cParsing.pHeader.CurrRessource;
          curPlanete.FLastRessourcesDate := DateTimeToUnix(Now);

          //FLastPageWebDL := cElement;



lExecutedDoUpdate:

          LastCurrDate := DateTimeToUnix(Now);

          i := GetTypeOfGID(Action.GID);

          // On ré-extrait le pointeur de LA PAGE WEB car il a été mis à jour
          //pElement := cElement.Valeurs.GetGidItem(Action.Gid);
          pElement := curPlanete.cElements.GetGidItem(Action.Gid);

          if pElement = nil then begin
             // impossible
              {$IFDEF DEBUG}
                  DoDebug('Erreur FATALE');
              {$ENDIF}

              Result := basERREUR_FATALE;
              exit;
          end;

          if i = CNT_ITEM_DESIGN_RECHERCHE then begin
             // La recherche est globale à toute les planètes du joueur en
             // cours, on modifie donc l'attribut de la classe actuelle
             allPlanetes.ActionDateFinRecherche := LastCurrDate + pElement.Duree;

          end else if i = CNT_ITEM_DESIGN_BATIMENT then begin
             // La construction est propre à chaque planète
             curPlanete.ActionDateFinBatiment := LastCurrDate + pElement.Duree;

             // en profite pour mettre à jour les ressources
             ProceedUpdateRessource(true, true);
             

          end else begin
              // Impossible
              // Mais ce cas a déjà été traité plus haut, donc on arrive
              // jamais ici théoriquement
              {$IFDEF DEBUG}
                  DoDebug('Erreur FATALE');
              {$ENDIF}

              Result := basERREUR_FATALE;
              exit;
          end;

          // Indique que l'action a été effectuée
          Action.Status := ACTION_STATUS_EFFECTUE;
          curPlanete.cActions.ActionEffectuee(Action);
          Result := basACTION_EFFECTUE;
          exit;

       end else begin
          // Sinon c'est un formulaire à remplir pour pouvoir contruire l'élément
          // On est donc dans le cas du Chantier Spatial (defense et vaisseaux)
          // Dans ce cas là, on doit vérifier si on a les ressources suffisantes
          // pour construire l'élément, car avec ou sans les ressources, le
          // formulaire existe et l'on peut mettre les valeurs que l'on veut.

          {$IFDEF DEBUG}
              DoDebug('Pas encore implémenté');
          {$ENDIF}

          Action.Status := ACTION_STATUS_GIDNONDISPONIBLE;
          curPlanete.cActions.ActionEffectuee(Action);
          
          Result := basGID_NONDISPONIBLE;
       end;

    end;



end;

procedure TPlayerGestionConstruct.Init;
begin
        // La recherche est commune à toute les planètes, donc gérée
        // au sein de cette classe
        allPlanetes.ActionDateFinRecherche:= 0;

        FConstructionAutoEnable     := false;

end;



function TPlayerGestionConstruct.TryExecuteActionPlanete: integer;
label ReDo1;
//var NextAct, NextAct2, NextAct3: PElementActionItem;
    //a1, a2, a3: integer;
    //iRedo, r: integer;

    //pe1: POGItemCost;


    //t1: integer;
    //CurrDate: int64;
begin

(*
    DoDebug('TryExecuteActionPlanete - Start');

    if FCurrentPlanete.cActions.Count = 0 then begin
       Result := 0;
       DoDebug('TryExecuteActionPlanete - Aucune action trouvée');
       exit;
    end;

    // On extrait la prochaine action, pour vérifier qu'il y en a bien une
    // avant d'effectuer le changement de planète sur le "site"
    a1 := FCurrentPlanete.cActions.GetIndexNextActionToDo;

    if a1 < 0 then begin
       // Aucune action à effectuer
       DoDebug('TryExecuteActionPlanete - Toute les actions ont déjà été effectuée - Aucune action à exécuter');
       Result := -1;
       exit;
    end;

    //
    // On sous entend que lors de l'éxécution précédente du programme, la
    // production de ressource pour cet élément a été réglé en fonction
    // des désirs de l'utilisateur
    //

    NextAct := FCurrentPlanete.cActions.Items[a1];

    if a1 = FCurrentPlanete.cActions.Count - 1 then begin
       // Derniere action de la liste
       // effectue tout simplement l'action
       DoDebug('TryExecuteActionPlanete - L''action à effectuer est la dernière de la liste');
       Result := ExecuteActionElement(NextAct);
       exit;
    end;

    DoDebug('TryExecuteActionPlanete - L''action à effectuer N''est PAS la dernière de la liste');


    // Vérification sur les ressources
    // FCurrentPlanete.pLastRessources
    pe1 := FCurrentPlanete.cElements.GetGidItem(NextAct.Gid);
    if pe1 <> nil then begin

       if pe1.Prix.Metal > FCurrentPlanete.pEstimatedRessources.Metal then begin
          // Pas assez de métal
          DoDebug(format('TryExecuteActionPlanete - Pas assez de métal, requis:%d  disponible:%d', [pe1.Prix.Metal, FCurrentPlanete.pEstimatedRessources.Metal]));
          Result := FNCT_RES_RESSOURCE_INSUFFISANTE;
          exit;

       end else if pe1.Prix.Cristal > FCurrentPlanete.pEstimatedRessources.Cristal then begin
          // Pas assez de Cristal
          DoDebug(format('TryExecuteActionPlanete - Pas assez de Cristal, requis:%d  disponible:%d', [pe1.Prix.Cristal, FCurrentPlanete.pEstimatedRessources.Cristal]));
          Result := FNCT_RES_RESSOURCE_INSUFFISANTE;
          exit;

       end else if pe1.Prix.Deuterium > FCurrentPlanete.pEstimatedRessources.Deuterium then begin
          // Pas assez de Cristal
          DoDebug(format('TryExecuteActionPlanete - Pas assez de Deuterium, requis:%d  disponible:%d', [pe1.Prix.Deuterium, FCurrentPlanete.pEstimatedRessources.Deuterium]));
          Result := FNCT_RES_RESSOURCE_INSUFFISANTE;
          exit;
       end;

       DoDebug('TryExecuteActionPlanete - Element connu et ressource suffisante pour le contruire');

    end else begin
       DoDebug('L''élément à construire est inconnu dans la liste des éléments - Exécution de l''action quand même');
    end;


    // Arrivé ici, on a assez de ressources pour construire l'élément


    CurrDate := DateTimeToUnix(Now);

    // Définit le type pour ce GID:
    t1 := GetTypeOfGID(NextAct.GID);

    if (t1 = CNT_ITEM_DESIGN_BATIMENT) and (FCurrentPlanete.ActionDateFinBatiment < CurrDate) then begin
       // La place est théoriquement libre
       // Sauf si il y a une autre construction

       DoDebug('TryExecuteActionPlanete - Action de type batiment, Place libre théoriquement');


       iRedo := 0;

    ReDo1:
       Inc(iRedo);
       Result := ExecuteActionElement(NextAct);

       if Result = ACTION_STATUS_EFFECTUE then begin
          // Meilleur des cas
          // On n'a pas besoin de se soucier des autres action, mis à part
          // pour l'ajustement de ressource

          // Ajuste les ressources pour construire le prochain élément
          AdjustRessourceForTheNextItem;

          // On peut quitter
          exit;

       end else if Result = CNT_ERROR_SHOULD_RELOGIN then begin
          // On devrait se relogger...
          r := ProceedLogin;

          if r <= 0 then begin
             // Echec de relogin
             DoDebug('TryExecuteActionPlanete - Echec de re-logging');
             Result := -1;
             exit;
          end;

          if iRedo > 1 then begin
             // Pas de boucle infinit
             Result := -1;
             exit;
          end else
             goto Redo1;

       end else if Result = FNCT_RES_RESSOURCE_INSUFFISANTE then begin
          // Pas assez de ressource
          DoDebug('TryExecuteActionPlanete - Pas assez de ressource');
          exit;

       end else if Result = FNCT_RES_DO_NEXT_ACTION then begin
          // Il semble impossible de construire l'élément en cours
          // Et on peut traiter l'action suivante

       end else if Result = ACTION_STATUS_GID_CANTBEBUILDWITHTHISPRODUCTION then begin
          // Cet élément ne peut pas être construit avec la production actuelle
          // Dans ce cas là, on va essayer de passer à l'élément suivant
          // ou de modifier la production acutelle


       end else if Result = ACTION_STATUS_GIDNONDISPONIBLE then begin
          // Même cas qu'au dessus

       end else if Result = FNCT_RES_AUTRECONSTRUCTION_EN_COURS then begin
          // Un élément est déjà en cours de construction
          // On doit attendre la fin de celui-ci
          // En attendant, on essaye de produire un autre type d'élément
          // (exemple: la recherche)
          // A condition que celui-ci ne soit pas trop loin dans la liste
          // et qu'il ne mette pas en péril la construction du premier élément


       end else begin
          // Autre erreur, théoriquement 'fatale'
          // On quitte
          DoDebug('TryExecuteActionPlanete - Erreur fatale');
          exit;
       end;



    end;


    //
    Result := FCurrentPlanete.cActions.GetGIDSetRessourceForThisItem(a1, true);

*)


end;



end.
